package com.lixin.web.netty.handler;

import cn.hutool.core.bean.BeanUtil;
import cn.hutool.core.util.StrUtil;
import com.lixin.exception.RequestException;
import com.lixin.model.request.Request;
import com.lixin.model.response.Response;
import com.lixin.web.netty.NettyServerStarter;
import com.lixin.web.webSocket.WebSocketManager;
import com.lixin.web.webSocket.WebSocketMethodMapper;
import io.netty.channel.ChannelHandler;
import io.netty.channel.ChannelHandlerContext;
import io.netty.channel.SimpleChannelInboundHandler;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;

import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.Map;

/**
 * Description:
 * Copyright:   Copyright (c)2023
 * Company:     sci
 *
 * @author: 张李鑫
 * @version: 1.0
 * Create at:   2023-07-22 20:43:22
 * <p>
 * Modification History:
 * Date         Author      Version     Description
 * ------------------------------------------------------------------
 * 2023-07-22     张李鑫                     1.0         1.0 Version
 */

@Slf4j
@Component
@ChannelHandler.Sharable
public class WebSocketRequestHandler<T> extends SimpleChannelInboundHandler<Request<T>> {


    @Autowired
    private WebSocketMethodMapper webSocketMethodMapper;

    public static final String SUB = "/";


    @Override
    protected void channelRead0(ChannelHandlerContext ctx, Request<T> request) {
        NettyServerStarter.ctxThreadLocal.set(ctx);
        String event = request.getEvent();
        if (StrUtil.isEmpty(event)) {
            throw new RequestException("event is empty");
        }
        //避免空指针
        String[] split = event.contains(SUB) ? event.split(SUB) : new String[]{"", ""};
        String pre = split[0];
        String func = split[1];

        if (!webSocketMethodMapper.hasFunc(split[0], split[1])) {
            throw new RequestException("request is error");
        }

        Method method = webSocketMethodMapper.getMethodMap().get(pre).get(func);

        //todo 设置request 真实的范型 这里简单的转换一下 后续可以在序列化的时候直接转换 不过目前来看比较复杂

        WebSocketManager webSocketManager = webSocketMethodMapper.getBean().get(pre);
        try {
            if (method.getParameterCount() == 0) {
                ctx.writeAndFlush(method.invoke(webSocketManager));
            } else {
                ctx.writeAndFlush(
                        method.invoke(
                                webSocketManager,
                                BeanUtil.toBean(request.getModel(),
                                        (Class<?>) method.getGenericParameterTypes()[0]))
                );
            }
        } catch (IllegalAccessException e) {
            throw new RuntimeException(e);
        } catch (InvocationTargetException e) {
            Throwable targetException = e.getTargetException();
            throw targetException instanceof RuntimeException ?
                    (RuntimeException) targetException :
                    new RuntimeException(targetException);
        } finally {
            NettyServerStarter.ctxThreadLocal.remove();
        }
    }
}

